package com.atguigu.guli.service.api.gateway.filter;

import com.atguigu.guli.service.base.result.ResultCodeEnum;
import com.atguigu.guli.service.base.utils.JwtHelper;
import com.google.gson.JsonObject;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

/*
全局鉴权处理
1、如果判断一个请求是否需要鉴权
	在需要鉴权的路径中添加一级路径 /auth
	请求时获取路径判断

2、需要鉴权的请求如何鉴权
	获取请求报文头中的token使用JwtHelper进行鉴权(token是否被篡改  是否过期)
3、鉴权失败 如何响应
	鉴权失败 返回需要登录的R对象

 */
@Component
public class GlobalAuthFilter implements GlobalFilter, Ordered {

    //鉴权是通过过滤器来实现的，每一个通过网关的请求都会被该过滤器过滤
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //通过交换机来获取请求和响应
        //交换机中处理请求和响应
        //rabbitMq中交换机
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        //通过交换机获取到的请求和响应来获取请求路径
        String path = request.getURI().getPath();//获取资源的路径
        AntPathMatcher matcher = new AntPathMatcher();//ant风格路径比较器
        boolean match = matcher.match("/api/**/auth/**", path);//比较传入的路径与过滤条件
        if (!match){
            //如果不包含过滤条件则放行
            return  chain.filter(exchange);
        }
        //包含则对该路径进行鉴权处理
        //鉴权的步骤
        /*
        解析请求头中的token 判断token是否过期或者被篡改

         */
        String token = request.getHeaders().getFirst("token");
        boolean b = JwtHelper.checkToken(token);
        if (b){
            //解析成功则表示鉴权通过
            return chain.filter(exchange);
        }
        //解析失败 给失败响应
        //设置自定义的响应报文
        //设置响应报文的格式和编码规则
        response.getHeaders().set("Content-Type","application/json;charset=UTF-8");
        //此时说明token过期或者被篡改
        JsonObject jsonObject = new JsonObject();//创建一个json对象(调用toString时可以直接转为json字符串)
        jsonObject.addProperty("code", ResultCodeEnum.LOGIN_AUTH.getCode());
        jsonObject.addProperty("message","gateway"+ResultCodeEnum.LOGIN_AUTH.getMessage());
        jsonObject.addProperty("success",ResultCodeEnum.LOGIN_AUTH.getSuccess());
        byte[] bytes = jsonObject.toString().getBytes(StandardCharsets.UTF_8);
        DataBuffer data = response.bufferFactory().wrap(bytes);//将bs 响应报文的字节数组转为缓存数据对象
        return response.writeWith(Mono.just(data));//将响应数据的缓存数据对象转为响应报文
    }

    @Override
    public int getOrder() {//排序等级 数字越小 等级越高
        return 0;
    }
}
